/* Created by Richard Fleming
 * Copyright 2008 Johnson County Community College
 * Free for non-commercial use
 */

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace XnaUtility.Control
{

    public enum MouseButton
    {
        LeftButton,
        RightButton,
        MiddleButton,
    }


    public class InputBase : GameComponent
    {
        #region "Properties and Variables"

        Game game;

        KeyboardState oldKeyboard;
        KeyboardState currentKeyboard;
        MouseState oldMouse;
        MouseState currentMouse;
        GamePadState[] oldPad;
        GamePadState[] currentPad;        

        bool addAsService;

        private bool disableKeyboard;
        private bool disableMouse;
        private bool disablePad;
        private Vector2 mouseDelta;
        private bool isMouseLocked;
        private Vector2 lockPoint;
        private Point lastMousePoint;
        private Point curMousePoint;

        public Point LastMousePoint { get { return lastMousePoint; } }
        public Point CurrentMousePoint { get { return curMousePoint; } }
	
        public Vector2 MouseDelta
        {
            get { return mouseDelta; }
            set { mouseDelta = value; }
        }
	
        public bool DisablePad
        {
            get { return disablePad; }
            set { disablePad = value; }
        }
	
        public bool DisableMouse
        {
            get { return disableMouse; }
            set { disableMouse = value; }
        }
	
        public bool DisableKeyboard
        {
            get { return disableKeyboard; }
            set { disableKeyboard = value; }
        }

        public Vector2 MousePosition
        {
            get { return new Vector2(currentMouse.X, currentMouse.Y); }
        }
	

        #endregion

        #region "Constructors and Intializers"

        public InputBase(Game game)
            : base(game)
        {
            this.game = game;
            addAsService = true;

            disableKeyboard = false;
            disableMouse = false;
            disablePad = false;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="game">Reference to current game</param>
        /// <param name="serviceAdd">Should this be added as a service?</param>
        public InputBase(Game game, bool serviceAdd)
            : base(game)
        {
            this.game = game;
            addAsService = serviceAdd;

            disableKeyboard = false;
            disableMouse = false;
            disablePad = false;
        }

        public override void Initialize()
        {

            if (!disablePad)
            {
                currentPad = new GamePadState[4];
                oldPad = new GamePadState[4];

                for (int i = 0; i < 4; i++)
                {
                    currentPad[i] = GamePad.GetState((PlayerIndex)i);
                    oldPad[i] = GamePad.GetState((PlayerIndex)i);
                }
            }

            if (!disableKeyboard)
            {
                oldKeyboard = Keyboard.GetState();
                currentKeyboard = Keyboard.GetState();
            }

            if (!disableMouse)
            {
                oldMouse = Mouse.GetState();
                currentMouse = Mouse.GetState();
                mouseDelta.X = 0;
                mouseDelta.Y = 0;
            }

            if (addAsService)
            {
                game.Services.AddService(typeof(InputBase), this);
            }

            base.Initialize();
        }

        #endregion

        public override void Update(GameTime gameTime)
        {
            if (!disableKeyboard)
            {
                oldKeyboard = currentKeyboard;
                currentKeyboard = Keyboard.GetState();
            }

            if (!disableMouse)
            {
                oldMouse = currentMouse;
                lastMousePoint = curMousePoint;
                currentMouse = Mouse.GetState();
                curMousePoint.X = (int)currentMouse.X;
                curMousePoint.Y = (int)currentMouse.Y;

                mouseDelta.X = currentMouse.X - oldMouse.X;
                mouseDelta.Y = currentMouse.Y - oldMouse.Y;

                if (isMouseLocked)
                {
                    Mouse.SetPosition((int)lockPoint.X, (int)lockPoint.Y);
                    currentMouse = Mouse.GetState();
                }
            }

            if (!disablePad)
            {
                for (int i = 0; i < 4; i++)
                {
                    oldPad[i] = currentPad[i];
                    currentPad[i] = GamePad.GetState((PlayerIndex)i);
                }
            }

            base.Update(gameTime);
        }

        #region "Keyboard Methods"

        public bool IsKeyDown(Keys key)
        {
            return currentKeyboard.IsKeyDown(key);
        }

        public bool IsKeyUp(Keys key)
        {
            return currentKeyboard.IsKeyUp(key);
        }

        public bool WasKeyPressed(Keys key)
        {
            return currentKeyboard.IsKeyDown(key) && oldKeyboard.IsKeyUp(key);
        }

        public bool WasKeyReleased(Keys key)
        {
            return currentKeyboard.IsKeyUp(key) && oldKeyboard.IsKeyDown(key);
        }

        #endregion

        #region "Mouse Methods"

        /// <summary>
        /// Locks the mouse position.  Assumes the lock point has been set
        /// </summary>
        public void LockMouse()
        {
            isMouseLocked = true;
        }

        /// <summary>
        /// Toggles the visibilty of the mouse cursor
        /// </summary>
        public void ToggleShowMouse()
        {
            game.IsMouseVisible = !game.IsMouseVisible;
        }

        /// <summary>
        /// Sets the visibilty of the mouse cursor
        /// </summary>
        /// <param name="isVisible">true = visible, false = not visible</param>
        public void SetCursorVisibility(bool isVisible)
        {
            game.IsMouseVisible = isVisible;
        }

        /// <summary>
        /// Locks the mouse position.
        /// </summary>
        /// <param name="lockPoint">The X,Y corodinate to lock the mouse to</param>
        public void LockMouse(Vector2 lockPoint)
        {
            LockMouse();
            this.lockPoint = lockPoint;
        }

        /// <summary>
        /// Locks the mosue position.
        /// </summary>
        /// <param name="width">lockPoint.X = width / 2</param>
        /// <param name="height">lockPoint.Y = height / 2</param>
        public void LockMouse(int width, int height)
        {
            LockMouse();
            this.lockPoint.X = width / 2;
            this.lockPoint.Y = height / 2;
        }

        /// <summary>
        /// Releases the lock on the mouse position
        /// </summary>
        public void UnlockMouse()
        {
            isMouseLocked = false;
        }

        /// <summary>
        /// Toggles the mouse lock.  Assumings the lock point has already been set.
        /// </summary>
        public void ToggleMouseLock()
        {
            isMouseLocked = !isMouseLocked;
        }

        public bool IsMouseButtonDown(MouseButton button)
        {
            switch (button)
            {
                case MouseButton.LeftButton:
                    return currentMouse.LeftButton == ButtonState.Pressed;

                case MouseButton.MiddleButton:
                    return currentMouse.MiddleButton == ButtonState.Pressed;

                case MouseButton.RightButton:
                    return currentMouse.RightButton == ButtonState.Pressed;

                default:
                    return false;
            }
        }

        public bool IsMouseButtonUp(MouseButton button)
        {
            switch (button)
            {
                case MouseButton.LeftButton:
                    return currentMouse.LeftButton == ButtonState.Released;

                case MouseButton.MiddleButton:
                    return currentMouse.MiddleButton == ButtonState.Released;

                case MouseButton.RightButton:
                    return currentMouse.RightButton == ButtonState.Released;

                default:
                    return false;
            }
        }

        public bool WasMouseButtonPressed(MouseButton button)
        {
            switch (button)
            {
                case MouseButton.LeftButton:
                    return currentMouse.LeftButton == ButtonState.Pressed && oldMouse.LeftButton == ButtonState.Released;

                case MouseButton.MiddleButton:
                    return currentMouse.MiddleButton == ButtonState.Pressed && oldMouse.MiddleButton == ButtonState.Released;

                case MouseButton.RightButton:
                    return currentMouse.RightButton == ButtonState.Pressed && oldMouse.RightButton == ButtonState.Released;

                default:
                    return false;
            }
        }

        public bool WasMouseButtonReleased(MouseButton button)
        {
            switch (button)
            {
                case MouseButton.LeftButton:
                    return currentMouse.LeftButton == ButtonState.Released && oldMouse.LeftButton == ButtonState.Pressed;

                case MouseButton.MiddleButton:
                    return currentMouse.MiddleButton == ButtonState.Released && oldMouse.MiddleButton == ButtonState.Pressed;

                case MouseButton.RightButton:
                    return currentMouse.RightButton == ButtonState.Released && oldMouse.RightButton == ButtonState.Pressed;

                default:
                    return false;
            }
        }

        #endregion

        #region "XBOX GamePad Methods"

        public bool IsPadButtonDown(Buttons button, PlayerIndex index)
        {
            int i = (int)index;

            switch (button)
            {
                case Buttons.A:
                    return currentPad[i].Buttons.A == ButtonState.Pressed;
                case Buttons.B:
                    return currentPad[i].Buttons.B == ButtonState.Pressed;
                case Buttons.Back:
                    return currentPad[i].Buttons.Back == ButtonState.Pressed;
                case Buttons.DPadDown:
                    return currentPad[i].DPad.Down == ButtonState.Pressed;
                case Buttons.DPadLeft:
                    return currentPad[i].DPad.Left == ButtonState.Pressed;
                case Buttons.DPadRight:
                    return currentPad[i].DPad.Right == ButtonState.Pressed;
                case Buttons.DPadUp:
                    return currentPad[i].DPad.Up == ButtonState.Pressed;
                case Buttons.LeftShoulder:
                    return currentPad[i].Buttons.LeftShoulder == ButtonState.Pressed;
                case Buttons.LeftStick:
                    return currentPad[i].Buttons.LeftStick == ButtonState.Pressed;
                case Buttons.RightShoulder:
                    return currentPad[i].Buttons.RightShoulder == ButtonState.Pressed;
                case Buttons.RightStick:
                    return currentPad[i].Buttons.RightStick == ButtonState.Pressed;
                case Buttons.Start:
                    return currentPad[i].Buttons.Start == ButtonState.Pressed;
                case Buttons.X:
                    return currentPad[i].Buttons.X == ButtonState.Pressed;
                case Buttons.Y:
                    return currentPad[i].Buttons.Y == ButtonState.Pressed;
                default:
                    return false;
            }
        }

        public bool IsPadButtonUp(Buttons button, PlayerIndex index)
        {
            int i = (int)index;

            switch (button)
            {
                case Buttons.A:
                    return currentPad[i].Buttons.A == ButtonState.Released;
                case Buttons.B:
                    return currentPad[i].Buttons.B == ButtonState.Released;
                case Buttons.Back:
                    return currentPad[i].Buttons.Back == ButtonState.Released;
                case Buttons.DPadDown:
                    return currentPad[i].DPad.Down == ButtonState.Released;
                case Buttons.DPadLeft:
                    return currentPad[i].DPad.Left == ButtonState.Released;
                case Buttons.DPadRight:
                    return currentPad[i].DPad.Right == ButtonState.Released;
                case Buttons.DPadUp:
                    return currentPad[i].DPad.Up == ButtonState.Released;
                case Buttons.LeftShoulder:
                    return currentPad[i].Buttons.LeftShoulder == ButtonState.Released;
                case Buttons.LeftStick:
                    return currentPad[i].Buttons.LeftStick == ButtonState.Released;
                case Buttons.RightShoulder:
                    return currentPad[i].Buttons.RightShoulder == ButtonState.Released;
                case Buttons.RightStick:
                    return currentPad[i].Buttons.RightStick == ButtonState.Released;
                case Buttons.Start:
                    return currentPad[i].Buttons.Start == ButtonState.Released;
                case Buttons.X:
                    return currentPad[i].Buttons.X == ButtonState.Released;
                case Buttons.Y:
                    return currentPad[i].Buttons.Y == ButtonState.Released;
                default:
                    return false;
            }
        }

        public bool WasPadButtonPressed(Buttons button, PlayerIndex index)
        {
            int i = (int)index;

            switch (button)
            {
                case Buttons.A:
                    return currentPad[i].Buttons.A == ButtonState.Pressed && oldPad[i].Buttons.A == ButtonState.Released;
                case Buttons.B:
                    return currentPad[i].Buttons.B == ButtonState.Pressed && oldPad[i].Buttons.B == ButtonState.Released;
                case Buttons.Back:
                    return currentPad[i].Buttons.Back == ButtonState.Pressed && oldPad[i].Buttons.Back == ButtonState.Released;
                case Buttons.DPadDown:
                    return currentPad[i].DPad.Down == ButtonState.Pressed && oldPad[i].DPad.Down == ButtonState.Released;
                case Buttons.DPadLeft:
                    return currentPad[i].DPad.Left == ButtonState.Pressed && oldPad[i].DPad.Left == ButtonState.Released;
                case Buttons.DPadRight:
                    return currentPad[i].DPad.Right == ButtonState.Pressed && oldPad[i].DPad.Right == ButtonState.Released;
                case Buttons.DPadUp:
                    return currentPad[i].DPad.Up == ButtonState.Pressed && oldPad[i].DPad.Up == ButtonState.Released;
                case Buttons.LeftShoulder:
                    return currentPad[i].Buttons.LeftShoulder == ButtonState.Pressed && oldPad[i].Buttons.LeftShoulder == ButtonState.Released;
                case Buttons.LeftStick:
                    return currentPad[i].Buttons.LeftStick == ButtonState.Pressed && oldPad[i].Buttons.LeftStick == ButtonState.Released;
                case Buttons.RightShoulder:
                    return currentPad[i].Buttons.RightShoulder == ButtonState.Pressed && oldPad[i].Buttons.RightShoulder == ButtonState.Released;
                case Buttons.RightStick:
                    return currentPad[i].Buttons.RightStick == ButtonState.Pressed && oldPad[i].Buttons.RightStick == ButtonState.Released;
                case Buttons.Start:
                    return currentPad[i].Buttons.Start == ButtonState.Pressed && oldPad[i].Buttons.Start == ButtonState.Released;
                case Buttons.X:
                    return currentPad[i].Buttons.X == ButtonState.Pressed && oldPad[i].Buttons.X == ButtonState.Released;
                case Buttons.Y:
                    return currentPad[i].Buttons.Y == ButtonState.Pressed && oldPad[i].Buttons.Y == ButtonState.Released;
                default:
                    return false;
            }
        }

        public bool WasPadButtonReleased(Buttons button, PlayerIndex index)
        {
            int i = (int)index;

            switch (button)
            {
                case Buttons.A:
                    return currentPad[i].Buttons.A == ButtonState.Released && oldPad[i].Buttons.A == ButtonState.Pressed;
                case Buttons.B:
                    return currentPad[i].Buttons.B == ButtonState.Released && oldPad[i].Buttons.B == ButtonState.Pressed;
                case Buttons.Back:
                    return currentPad[i].Buttons.Back == ButtonState.Released && oldPad[i].Buttons.Back == ButtonState.Pressed;
                case Buttons.DPadDown:
                    return currentPad[i].DPad.Down == ButtonState.Released && oldPad[i].DPad.Down == ButtonState.Pressed;
                case Buttons.DPadLeft:
                    return currentPad[i].DPad.Left == ButtonState.Released && oldPad[i].DPad.Left == ButtonState.Pressed;
                case Buttons.DPadRight:
                    return currentPad[i].DPad.Right == ButtonState.Released && oldPad[i].DPad.Right == ButtonState.Pressed;
                case Buttons.DPadUp:
                    return currentPad[i].DPad.Up == ButtonState.Released && oldPad[i].DPad.Up == ButtonState.Pressed;
                case Buttons.LeftShoulder:
                    return currentPad[i].Buttons.LeftShoulder == ButtonState.Released && oldPad[i].Buttons.LeftShoulder == ButtonState.Pressed;
                case Buttons.LeftStick:
                    return currentPad[i].Buttons.LeftStick == ButtonState.Released && oldPad[i].Buttons.LeftStick == ButtonState.Pressed;
                case Buttons.RightShoulder:
                    return currentPad[i].Buttons.RightShoulder == ButtonState.Released && oldPad[i].Buttons.RightShoulder == ButtonState.Pressed;
                case Buttons.RightStick:
                    return currentPad[i].Buttons.RightStick == ButtonState.Released && oldPad[i].Buttons.RightStick == ButtonState.Pressed;
                case Buttons.Start:
                    return currentPad[i].Buttons.Start == ButtonState.Released && oldPad[i].Buttons.Start == ButtonState.Pressed;
                case Buttons.X:
                    return currentPad[i].Buttons.X == ButtonState.Released && oldPad[i].Buttons.X == ButtonState.Pressed;
                case Buttons.Y:
                    return currentPad[i].Buttons.Y == ButtonState.Released && oldPad[i].Buttons.Y == ButtonState.Pressed;
                default:
                    return false;
            }
        }

        public Vector2 GetLeftStickValue(PlayerIndex index)
        {
            return currentPad[(int)index].ThumbSticks.Left;
        }

        public Vector2 GetRightStickValue(PlayerIndex index)
        {
            return currentPad[(int)index].ThumbSticks.Right;
        }

        public float GetLeftTriggerValue(PlayerIndex index)
        {
            return currentPad[(int)index].Triggers.Left;
        }

        public float GetRightTriggerValue(PlayerIndex index)
        {
            return currentPad[(int)index].Triggers.Right;
        }
        #endregion
    }
}
